package com.gorillalogic.scrummonkey.test {
	import com.gorillalogic.scrummonkey.dms.DmsUtils;
	import com.gorillalogic.scrummonkey.dms.Project;
	import com.gorillalogic.scrummonkey.dms.ProjectService;
	import com.gorillalogic.scrummonkey.dms.Release;
	import com.gorillalogic.scrummonkey.dms.ReleaseService;
	import com.gorillalogic.scrummonkey.dms.Iteration;
	import com.gorillalogic.scrummonkey.dms.IterationService;
	import com.gorillalogic.scrummonkey.dms.Objective;
	import com.gorillalogic.scrummonkey.dms.ObjectiveService;
	
	import mx.collections.ArrayCollection;
	
	import org.flexunit.Assert;
	import org.hamcrest.assertThat;
	import org.hamcrest.collection.everyItem;
	import org.hamcrest.collection.hasItems;
	import org.hamcrest.object.equalTo;
	import org.hamcrest.object.nullValue;

	/**
	 * Create simple hierarchy, initiate Data Management, then delete a Release
	 */
	public class ReleaseTest2 extends BaseTest {

		/**
		 * Create hierarchy: P,R
		 */
		[Test(async,order=1)]
		public function create():void {
			var p:Project = new Project('proj1');
			var r1:Release = new Release('rel1');
			var i1:Iteration = new Iteration('it1');
			var o1:Objective = new Objective('obj1');
			var o2:Objective = new Objective('obj2');

			//wireup hierarchy
			p.releases.addItem(r1);
			r1.project = p;

			r1.iterations.addItem(i1);
			i1.release = r1;

			//wireup objectives on project
			p.objectives.addItem(o1);
			p.objectives.addItem(o2);
			o1.project = p;
			o2.project = p;

			//wireup objectives on releases
			r1.objectives.addItem(o1);
			r1.objectives.addItem(o2);
			o1.release = r1;
			o2.release = r1;

			//wireup objectives on iterations
			i1.objectives.addItem(o1);
			o1.iteration = i1;

			callAndThenOrFault(ProjectService.service.createProject(p), create2, null, 5000);
		}

		private function create2(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), create3);
		}

		private function create3(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			//verify release
			Assert.assertEquals('Bad number of releases', 1, project.releases.length);
			var release:Release = project.releases.getItemAt(0) as Release;
			Assert.assertTrue('Bad release name', 'rel1', release.name);
			Assert.assertEquals("Bad release's project name", 'proj1', release.project.name);

			//verify objectives on project
			Assert.assertEquals('Bad number of objectives on project', 2, project.objectives.length);
			var o1:Objective = project.objectives.getItemAt(0) as Objective;
			var o2:Objective = project.objectives.getItemAt(1) as Objective;
			assertThat('Bad objective names', [o1.name,o2.name], hasItems('obj1','obj2'));
			assertThat("Bad objective's project name", [o1.project.name,o2.project.name], everyItem(equalTo('proj1')));
			assertThat("Bad objective's release name", [o1.release.name,o2.release.name], everyItem(equalTo('rel1')));

			callAndThenOrFault(ReleaseService.service.getByName('rel1'), create4);
		}

		private function create4(data:Object, passThroughData:Object):void {
			var release:Release = (data.result as ArrayCollection).getItemAt(0) as Release;
			Assert.assertEquals('Bad release name', 'rel1', release.name);
			Assert.assertEquals("Bad release's project name", 'proj1', release.project.name);

			//verify iteration
			Assert.assertEquals('Bad number of iterations', 1, release.iterations.length);
			var iteration:Iteration = release.iterations.getItemAt(0) as Iteration;
			Assert.assertTrue('Bad iteration name', 'it1', iteration.name);
			Assert.assertEquals("Bad iteration's release name", 'rel1', iteration.release.name);

			//verify objectives on release
			Assert.assertEquals('Bad number of objectives on release', 2, release.objectives.length);
			var o1:Objective = release.objectives.getItemAt(0) as Objective;
			var o2:Objective = release.objectives.getItemAt(1) as Objective;
			assertThat('Bad objective names', [o1.name,o2.name], hasItems('obj1','obj2'));
			assertThat("Bad objective's project name", [o1.project.name,o2.project.name], everyItem(equalTo('proj1')));
			assertThat("Bad objective's release name", [o1.release.name,o2.release.name], everyItem(equalTo('rel1')));

			callAndThenOrFault(IterationService.service.getByName('it1'), create5);
		}

		private function create5(data:Object, passThroughData:Object):void {
			var iteration:Iteration = (data.result as ArrayCollection).getItemAt(0) as Iteration;
			Assert.assertTrue('Bad iteration name', 'it1', iteration.name);
			Assert.assertEquals("Bad iteration's release name", 'rel1', iteration.release.name);

			//verify objectives on iteration
			Assert.assertEquals('Bad number of objectives on iteration', 1, iteration.objectives.length);
			var objective:Objective = iteration.objectives.getItemAt(0) as Objective;
			Assert.assertTrue('Bad objective name', 'obj1', objective.name);
			Assert.assertEquals("Bad iteration's project name", 'proj1', objective.project.name);
			Assert.assertEquals("Bad iteration's release name", 'rel1', objective.release.name);
			Assert.assertEquals("Bad iteration's iteration name", 'it1', objective.iteration.name);
		}


		/**
		 * Delete R
		 */
		[Test(async,order=2)]
		public function deleteRelease():void {
			callAndThenOrFault(ReleaseService.service.getByName('rel1'), deleteRelease2);
		}

		private function deleteRelease2(data:Object, passThroughData:Object):void {
			var release:Release = (data.result as ArrayCollection).getItemAt(0) as Release;
			Assert.assertEquals('Bad release name', 'rel1', release.name);

			callAndThenOrFault(ReleaseService.service.deleteRelease(release), deleteRelease3);
		}

		private function deleteRelease3(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), deleteRelease4);
		}

		private function deleteRelease4(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			//verify release is gone
			Assert.assertEquals('Release not deleted', 0, project.releases.length);

			//verify objectives on project
			Assert.assertEquals('Bad number of objectives on project', 2, project.objectives.length);
			var o1:Objective = project.objectives.getItemAt(0) as Objective;
			var o2:Objective = project.objectives.getItemAt(1) as Objective;
			assertThat('Bad objective names', [o1.name,o2.name], hasItems('obj1','obj2'));
			assertThat("Bad objective's project name", [o1.project.name,o2.project.name], everyItem(equalTo('proj1')));
			assertThat("Bad objective's release", [o1.release,o2.release], everyItem(nullValue()));
			assertThat("Bad objective's iteration", [o1.iteration,o2.iteration], everyItem(nullValue()));

			callAndThenOrFault(ReleaseService.service.getByName('rel1'), deleteRelease5);
			callAndThenOrFault(IterationService.service.getByName('it1'), deleteRelease6);
		}

		private function deleteRelease5(data:Object, passThroughData:Object):void {
			var releases:ArrayCollection = data.result as ArrayCollection;
			Assert.assertEquals('Release not deleted', 0, releases.length);
		}

		private function deleteRelease6(data:Object, passThroughData:Object):void {
			var iterations:ArrayCollection = data.result as ArrayCollection;
			Assert.assertEquals('Iteration not deleted', 0, iterations.length);
		}


		/**
		 * Cleanup everything
		 */
		[Test(async,order=3)]
		public function cleanup():void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), cleanup2);
		}

		private function cleanup2(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			callAndThenOrFault(ProjectService.service.deleteProject(project), cleanup3);
		}

		private function cleanup3(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), cleanup4, null, 5000, 'proj1');
			callAndThenOrFault(ReleaseService.service.getByName('rel1'), cleanup4, null, 5000, 'rel1');
			callAndThenOrFault(IterationService.service.getByName('it1'), cleanup4, null, 5000, 'it1');
			callAndThenOrFault(ObjectiveService.service.getByName('obj1'), cleanup4, null, 5000, 'obj1');
			callAndThenOrFault(ObjectiveService.service.getByName('obj2'), cleanup4, null, 5000, 'obj2');
		}

		private function cleanup4(data:Object, passThroughData:Object):void {
			var entities:ArrayCollection = data.result as ArrayCollection;
			Assert.assertEquals('Cleanup failed on "' + passThroughData.toString() + '"', 0, entities.length);
		}
	}
}